package net.pulseproject.router.config.dependency;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashSet;
import java.util.Set;

import net.pulseproject.commons.misc.collection.Filter;
import net.pulseproject.commons.misc.collection.Matcher;
import net.pulseproject.router.config.parser.LineConfig;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

public class LineConfigFilter extends Filter<LineConfig> {

	private static final Log LOG = LogFactory.getLog(LineConfigFilter.class);
	
	private final NoOutgoingModulesMatcher noOutgoingModulesMatcher = new NoOutgoingModulesMatcher();
	
	
	public final Collection<LineConfig> filterNoOutgoingModules(final Collection<LineConfig> allConfigs) {
		LOG.debug("filterNoOutgoingModules(allConfigs)");
		return this.filter(allConfigs, this.noOutgoingModulesMatcher);
	}
	

	public final Collection<LineConfig> filterWithTheseOutgoingModules(final Collection<LineConfig> allConfigs, 
			final Collection<LineConfig> yetAvailableConfigs) {
		LOG.debug("filterWithTheseOutgoingModuleIds(allConfigs, yetAvailableConfigs)");
		if(yetAvailableConfigs == null) { throw new IllegalArgumentException("yetAvailableConfigs == null"); }
		
		final Collection<String> yetAvailableIds = new ArrayList<String>(yetAvailableConfigs.size());
		for (final LineConfig currentConfig : yetAvailableConfigs) {
			yetAvailableIds.add(currentConfig.getId());
		}
		LOG.trace("filterWithTheseOutgoingModuleIds(..) ... " +
				"yetAvailableIds = " + Arrays.toString(yetAvailableIds.toArray()));
		
		return this.filter(allConfigs, new LimitedOutgoingIdsMatcher(yetAvailableIds));
	}
	

	private static class NoOutgoingModulesMatcher implements Matcher<LineConfig> {
		NoOutgoingModulesMatcher() { /* nothing to do, just to avoid synthetic access */ }
		@Override
		public final boolean matches(final LineConfig instance) {
			return instance.getOutgoingIds().isEmpty();
		}
	}
	
	private static class LimitedOutgoingIdsMatcher implements Matcher<LineConfig> {
		private final Collection<String> yetAvailableIds;
		
		public LimitedOutgoingIdsMatcher(final Collection<String> yetAvailableIds) {
			this.yetAvailableIds = yetAvailableIds;
		}

		@Override
		public boolean matches(final LineConfig instance) {
			final Set<String> demandingIds = new HashSet<String>(instance.getOutgoingIds());
			demandingIds.removeAll(this.yetAvailableIds);
			return demandingIds.isEmpty();
		}
	}
}
